#pragma once
#include"LockGuard.hpp"
#include<queue>

const int g_DefaultCap=5;

template <class T>
class BlockQueue
{
private:
    bool isQueueEmpty()
    {
        return _bq.size()==0;
    }
    bool isQueueFull()
    {
        return _bq.size()==_capacity;
    }
public:
    BlockQueue(int capacity=g_DefaultCap)
        :_capacity(capacity)
    {
        pthread_mutex_init(&_mutex,nullptr);
        pthread_cond_init(&_prod,nullptr);
        pthread_cond_init(&_cons,nullptr);
    }
    void push(const T& in)
    {
        LockGuard lockguard(&_mutex);
        while(isQueueFull())
        {
            pthread_cond_wait(&_prod,&_mutex);
        }
        _bq.push(in);
        pthread_cond_signal(&_cons);
    }
    void pop(T* out)
    {
        LockGuard lockguard(&_mutex);
        while(isQueueEmpty())
        {
            pthread_cond_wait(&_cons,&_mutex);
        }
        *out=_bq.front();
        _bq.pop();
        pthread_cond_signal(&_prod);
    }
    ~BlockQueue()
    {
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_prod);
        pthread_cond_destroy(&_cons);
    }
private:
    queue<T> _bq;
    int _capacity;
    pthread_mutex_t _mutex;
    pthread_cond_t _prod;
    pthread_cond_t _cons;
};
// #pragma once
// #include"LockGuard.hpp"
// #include<queue>

// using namespace std;

// #define int g_DefaultCap=5;

// template <class T>
// class BlockQueue
// {
// public:
//     BlockQueue(int capacity=g_DefaultCap)
//         :_capacity(capacity)
//     {
//         pthread_mutex_init(mutex,nullptr);
//         pthread_cond_init(prod,nullptr);
//         pthread_cond_init(cons,nullptr);
//     }
//     void push(const T& in)
//     {
//         LockGuard lockguard(_mutex);
//         while(isQueueFull())
//         {
//             pthread_cond_wait(_prod,mutex);
//         }
//         _bq.push(in);
//         pthread_cond_signal(_cons);
//     }
//     void push(T* out)
//     {
//         LockGuard lockguard(_mutex);
//         while(isQueueEmpty())
//         {
//             pthread_cond_wait(_cons,_mutex);
//         }
//         *out=_bq.front();
//         _bq.pop();
//         pthread_cond_signal(_prod);
//     }
//     ~BlockQueue()
//     {
//         pthread_mutex_destroy(_mutex);
//         pthread_cond_destroy(_prod);
//         pthread_cond_destroy(_cons);
//     }
// private:
//     bool isQueueEmpty()
//     {
//         return _bq.size()==0;
//     }
//     bool isQueueFull()
//     {
//         return _bq.size()==_capacity;
//     }
// private:
//     queue<T> _bq;
//     int _capacity;
//     pthread_mutex_t* _mutex;
//     pthread_cond_t* _prod;
//     pthread_cond_t* _cons;
// };
